home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 2.iso / STUTTGART / LANG / C / LIB / UNIXLIB37B / !UnixLib37 / src / signal / c / post < prev    next >
Text File  |  1996-11-09  |  10KB  |  351 lines

  1. /****************************************************************************
  2.  *
  3.  * $Source: /unixb/home/unixlib/source/unixlib37/src/signal/c/RCS/post,v $
  4.  * $Date: 1996/11/06 22:01:42 $
  5.  * $Revision: 1.2 $
  6.  * $State: Rel $
  7.  * $Author: unixlib $
  8.  *
  9.  * $Log: post,v $
  10.  * Revision 1.2  1996/11/06 22:01:42  unixlib
  11.  * Yet more changes by NB, PB and SC.
  12.  *
  13.  * Revision 1.1  1996/10/30 22:04:51  unixlib
  14.  * Initial revision
  15.  *
  16.  ***************************************************************************/
  17.  
  18. static const char rcs_id[] = "$Id: post,v 1.2 1996/11/06 22:01:42 unixlib Rel $";
  19.  
  20. /* signal.c.post: Written by Nick Burrett, 27 August 1996.  */
  21.  
  22. #include <stdlib.h>
  23. #include <signal.h>
  24. #include <stdio.h>
  25. #include <errno.h>
  26. #include <sys/wait.h>
  27.  
  28. #include <sys/os.h>
  29. #include <sys/unix.h>
  30. #include <unixlib/sigstate.h>
  31.  
  32. /* #define DEBUG */
  33.  
  34. void
  35. __unixlib_default_sigaction (struct unixlib_sigstate *ss)
  36. {
  37.   int signo;
  38.  
  39.   sigemptyset (&ss->actions[0].sa_mask);
  40.   ss->actions[0].sa_flags = SA_RESTART;
  41.   ss->actions[0].sa_handler = SIG_DFL;
  42.  
  43.   /* Set all signals to their defaults.  */
  44.   for (signo = 1; signo < NSIG; ++signo)
  45.     ss->actions[signo] = ss->actions[0];
  46. }
  47.  
  48.  
  49. void __unixlib_internal_post_signal (struct unixlib_sigstate *ss,
  50.                           int signo, int sigcode, int sigerror)
  51. {
  52.   enum { stop, ignore, core, term, handle } act;
  53.   __sighandler_t handler;
  54.   struct unixlib_signal_preempt *pe;
  55.   sighandler_t (*preempt) (int, int, int) = NULL;
  56.   sigset_t pending;
  57.   int ss_suspended;
  58.  
  59. post_signal:
  60. #ifdef DEBUG
  61.   printf ("__unixlib_internal_post_signal: sigstate = %x, signo = %d\n", (int)ss, signo);
  62. #endif
  63.  
  64.   /* Increment the number of signals this process has received.  */
  65.   __u->usage.ru_nsignals++;
  66.  
  67.   /* Support for pre-emptive handlers.  */
  68.   for (pe = __u->sigpreempt[signo]; pe != NULL; pe = pe->next)
  69.     if (sigcode >= pe->first && sigcode <= pe->last)
  70.       {
  71.         preempt = pe->handler;
  72.         break;
  73.       }
  74.  
  75.   handler = SIG_DFL;
  76.   if (preempt)
  77.     {
  78.       /* Let the preempting handle examine the thread.
  79.          If it returns SIG_DFL, we run the normal handler;
  80.          otherwise we use the handler it returns.  */
  81. #ifdef DEBUG
  82.       os_print ("\r\n__unixlib_internal_post_signal: running a signal pre-empter\r\n");
  83. #endif
  84.       handler = (*preempt) (0, signo, sigcode);
  85.     }
  86.  
  87.   ss_suspended = 0;
  88.  
  89. #ifdef DEBUG
  90.   printf ("__unixlib_internal_post_signal: Do the handling\n");
  91. #endif
  92.  
  93.   if (handler != SIG_DFL)
  94.     /* Run the preemption-provided handler.  */
  95.     act = handle;
  96.   else
  97.     {
  98.       /* Do normal handling.  */
  99.  
  100.       handler = ss->actions[signo].sa_handler;
  101. #ifdef DEBUG
  102.       printf ("__unixlib_internal_post_signal: handler = %x\n", (int)handler);
  103. #endif
  104.  
  105.       if (handler == SIG_DFL)
  106.         /* Figure out the default action for this signal.  */
  107.         switch (signo)
  108.           {
  109.           case 0:
  110.             /* Special signo used for posting any pending signals.  */
  111.             act = ignore;
  112.             break;
  113.  
  114.       case SIGTTIN:
  115.       case SIGTTOU:
  116.       case SIGSTOP:
  117.       case SIGTSTP:
  118.         /* Signals that will stop a process.  */
  119.         act = stop;
  120.         break;
  121.  
  122.       case SIGCONT:
  123.       case SIGIO:
  124.       case SIGURG:
  125.       case SIGCHLD:
  126.       case SIGWINCH:
  127.         /* Signals that can otherwise be ignored.  */
  128.         act = ignore;
  129.         break;
  130.  
  131.       case SIGQUIT:
  132.       case SIGILL:
  133.       case SIGTRAP:
  134.       case SIGIOT:
  135.       case SIGEMT:
  136.       case SIGFPE:
  137.       case SIGBUS:
  138.       case SIGSEGV:
  139.       case SIGSYS:
  140.         /* Fatal signals that will cause a core dump.  */
  141.         act = core;
  142.         break;
  143.  
  144.       case SIGINFO:
  145.         if (__u->pgrp == __u->pid)
  146.           {
  147.             /* We provide a default handler for SIGINFO since
  148.                there is no user-specified handler.  */
  149.         act = handle;
  150.         handler = __unixlib_siginfo_handler;
  151.           }
  152.         else
  153.           act = ignore;
  154.         break;
  155.  
  156.       default:
  157.         /* All other signals will cause a process termination.  */
  158.         act = term;
  159.         break;
  160.       }
  161.       else if (handler == SIG_IGN)
  162.     act = ignore;
  163.       else
  164.     act = handle;
  165.  
  166.       if (sigmask (signo) & (sigmask (SIGTTIN) | sigmask (SIGTTOU)
  167.                              | sigmask (SIGSTOP) | sigmask (SIGTSTP)))
  168.     /* Stop signals clear a pending SIGCONT even if they
  169.        are handled or ignored (but not if preempted).  */
  170.     sigdelset (&ss->pending, SIGCONT);
  171.       else if (signo == SIGCONT)
  172.         {
  173.           /* Even if handled or ignored (but not preempted),
  174.              SIGCONT clears stop signals and resumes the process.  */
  175.           sigdelset (&ss->pending, SIGTTIN);
  176.           sigdelset (&ss->pending, SIGTTOU);
  177.           sigdelset (&ss->pending, SIGSTOP);
  178.           sigdelset (&ss->pending, SIGTSTP);
  179.           /* Resume all our children.  */
  180.           ss_suspended = 1;
  181.           __u->status.stopped = 0;
  182.         }
  183.     }
  184.  
  185. #ifdef DEBUG
  186.   printf ("__unixlib_internal_post_signal: act = %d\n", act);
  187. #endif
  188.  
  189.   if (__u->orphaned && act == stop &&
  190.       (signo & (sigmask (SIGTTIN) | sigmask (SIGTTOU) | sigmask (SIGTSTP))))
  191.     {
  192.       /* If we would ordinarily stop for a job control signal, but we are
  193.      orphaned so noone would ever notice and continue us again, we just
  194.      quietly die, alone and in the dark.  */
  195.       sigcode = signo;
  196.       signo = SIGKILL;
  197.       act = term;
  198.     }
  199.  
  200.   /* Handle a blocked signal.  */
  201.   if ((sigismember (&ss->blocked, signo) && act != ignore)
  202.       || (signo != SIGKILL && __u->stopped))
  203.     {
  204.       sigaddset (&ss->pending, signo);
  205.       /* Save the code to be given to the handler when SIGNO is unblocked.  */
  206.       ss->pending_data[signo].code = sigcode;
  207.       ss->pending_data[signo].error = sigerror;
  208.       act = ignore;
  209.     }
  210.  
  211. #ifdef DEBUG
  212.   printf ("__unixlib_internal_post_signal: Do the chosen action\n");
  213. #endif
  214.   /* Perform the chosen action for the signal.  */
  215.   switch (act)
  216.     {
  217.     case stop:
  218. #ifdef DEBUG
  219.       printf ("__unixlib_internal_post_signal: stop\n");
  220. #endif
  221.       if (! __u->status.stopped)
  222.         {
  223.           /* Stop all our threads, and mark ourselves stopped.  */
  224.           __u->status.stopped = 1;
  225.         }
  226.       /* Wake up sigsuspend. */
  227.       sigwakeup ();
  228.       break;
  229.  
  230.     case ignore:
  231. #ifdef DEBUG
  232.       printf ("__unixlib_internal_post_signal: ignore\n");
  233. #endif
  234.       /* Nobody cares about this signal.  */
  235.       break;
  236.  
  237.     case term: /* Time to die.  */
  238.     case core: /* and leave a rotting corpse.  */
  239.     death:
  240.       /* Stop all other threads in our task.  */
  241.       /* No more user instructions wil be executed. */
  242.       {
  243.         int status = W_EXITCODE (0, signo);
  244.         /* Do a core dump if desired. Only set the wait status bit saying
  245.            we in fact dumped core if the operation was actually successful.  */
  246. #ifdef DEBUG
  247.     printf ("__unixlib_internal_post_signal: term/core\n");
  248. #endif
  249.     if (act == term)
  250.       __write_termination (signo, sigcode, sigerror);
  251.         else if (act == core && __write_corefile (signo, sigcode, sigerror))
  252.           status |= WCOREFLAG;
  253.  
  254.         /* Die, returning information about how we died.  */
  255.         _exit (status);
  256.         /* Never reached.  */
  257.       }
  258.      break;
  259.  
  260.     case handle:
  261.       /* Call a handler for this signal.  */
  262.       {
  263.         sigset_t blocked;
  264.         int flags;
  265. #ifdef DEBUG
  266.         printf ("__unixlib_internal_post_signal: handle\n");
  267. #endif
  268.     /* We're going to handle this signal now, so remove it from
  269.        the pending list.  */
  270.         sigdelset (&ss->pending, signo);
  271.  
  272.         /* Block SIGNO and requested signals while running the handler.  */
  273.     blocked = ss->blocked;
  274.         ss->blocked |= sigmask (signo) | ss->actions[signo].sa_mask;
  275.     flags = ss->actions[signo].sa_flags;
  276.         /* Re-instate the default signal handler.  We do this before executing
  277.            the signal handler because a new handler might be setup whilst
  278.            executing the signal handler.  */
  279.         ss->actions[signo].sa_handler = SIG_DFL;
  280.       ss->actions[signo].sa_flags = SA_RESTART;
  281.       sigemptyset (&ss->actions[signo].sa_mask);
  282.  
  283.         /* Call the function to set the thread up to run the signal
  284.            handler, and preserve its old context.  */
  285.         if (__unixlib_setup_sighandler (ss, handler, signo, sigcode, flags))
  286.           {
  287.             /* We got a fault setting up the stack frame for the handler.
  288.                Nothing to do but die.  */
  289.             sigcode = signo;
  290.             signo = SIGILL;
  291.             act = core;
  292.             goto death;
  293.           }
  294.         /* If we reach here, we have successfully executed the signal handler.
  295.            All that is left is to restore the defaults.  */
  296.  
  297.         /* Re-instate the original sigset.  */
  298.         ss->blocked = blocked;
  299.         break;
  300.       }
  301.     }
  302.  
  303. #ifdef DEBUG
  304.   printf ("__unixlib_internal_post_signal: Deliver pending signals\n");
  305. #endif
  306.   /* Deliver pending signals.  */
  307.  
  308.   if (!__u->stopped && (pending = ss->pending & ~ss->blocked))
  309.     {
  310.       for (signo = 1; signo < NSIG; ++signo)
  311.         if (sigismember (&pending, signo))
  312.           {
  313.             sigdelset (&ss->pending, signo);
  314.             sigcode = ss->pending_data[signo].code;
  315.             sigerror = ss->pending_data[signo].error;
  316.             goto post_signal;
  317.           }
  318.     }
  319.  
  320.   ss->currently_handling = 0;
  321.   /* No more signals pending.  */
  322.   sigwakeup ();
  323. }
  324.  
  325. void __unixlib_raise_signal (struct unixlib_sigstate *ss,
  326.                       int signo, int sigcode, int sigerror)
  327. {
  328.   if (ss == NULL)
  329.     ss = &__u->sigstate;
  330.  
  331.   /* Mark signo as pending to be delivered.  */
  332.   sigaddset (&ss->pending, signo);
  333.   ss->pending_data[signo].code = sigcode;
  334.   ss->pending_data[signo].error = sigerror;
  335.  
  336.   if (!ss->currently_handling)
  337.     {
  338.       /* Post the signal if we are not already handling a signal.  */
  339.       ss->currently_handling = 1;
  340.       __unixlib_internal_post_signal (ss, signo, sigcode, sigerror);
  341.     }
  342. #ifdef DEBUG
  343.   else
  344.     {
  345.       os_print ("\n\r__unixlib_raise_signal: signal ");
  346.       os_print (sys_siglist[signo]);
  347.       os_print (" is pending for delivery\r\n");
  348.     }
  349. #endif
  350. }
  351.